#pragma once
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"
#include "Common.hpp"
#include "Intaddr.hpp"
#include"ThreadPool.hpp"
#include<functional>

#define BACKLOG 8
const uint16_t gport = 8899;
using namespace LogModule;
using namespace ThreadPoolModule;

//远程命令的执行
using handler_t = std::function<std::string(std::string&)>;

class TcpServer
{
    //version-3
    using task_t =std::function<void()>;//这个任务类型要与线程池中处理任务的类型相同
    
    //version-2
    struct ThreadData
    {
        int sockfd;
        TcpServer* self;
    };

public:
    TcpServer(handler_t handler , uint16_t port = gport)
        : _handler(handler) , _port(port), _isrunning(false)
    {
    }
    void InitServer()
    {
        // 1.创建socket文件
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0); // 没有Int  这里如果定义了一个变量  _sockfd的值就是没有变化的
        if (_listensockfd < 0)                             // 加 int 会变成局部变量，导致成员变量未被修改。
        {
            LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success, sockfd is : " << _listensockfd;

        // 2.1填充网络信息
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local)); // 先置零
        local.sin_family = AF_INET;
        local.sin_port = htons(_port); // 要被发送给对方的，即要发到网络中！
        local.sin_addr.s_addr = INADDR_ANY;

        // 2.2 bind
        int n = ::bind(_listensockfd, CONV(&local), sizeof(local));
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success";

        // 3. cs,tcp是面向连接的，就要求tcp随时随地等待被连接
        // tcp 需要将socket设置成为监听状态

        n = listen(_listensockfd, BACKLOG); // backlog不建议为0 或者太大
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            Die(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success, sockfd is : " << _listensockfd;

        //进程回收的阻塞问题解决方案2:
        // ::signal(SIGCHLD, SIG_IGN); // 子进程退出，OS会自动回收资源，不用在wait了  适用于父进程不关心子进程退出状态的情况（如简单的并发任务）。
        //如果父进程需要知道子进程的退出状态（如是否正常退出、返回值等），则不能忽略 SIGCHLD，而应该使用 wait() 或 waitpid()。
    }
    void HandlerRequest(int sockfd) // TCP也是全双工的  TCP面向字节流
    {
        LOG(LogLevel::INFO) << "HandlerRequest sockfd is " << sockfd;
        char inbuffer[4096];
        std::string package;
        //长任务
        while (true)
        {

            ssize_t n = ::recv(sockfd, inbuffer, sizeof(inbuffer) - 1, 0); // read读取是不完善
            if (n > 0)
            {
                inbuffer[n] = 0;
                LOG(LogLevel::INFO) << "\n" << inbuffer;
                package += inbuffer; // ?? // len\r\n{json}\r\n

                std::string cmd_result = _handler(package);
                if(cmd_result.empty()) continue; //TODO

                ::send(sockfd, cmd_result.c_str(), cmd_result.size(), 0); // 写入也是不完善
            }
            else if (n == 0)
            {
                // read如果返回值为0 ,表示client退出
                LOG(LogLevel::INFO) << "client Quit" << sockfd;
                break;
            }
            else
            {
                // read返回值小于0 ,表示读取失败
                LOG(LogLevel::WARNNING) << "read error" << strerror(errno);
                break;
            }
        }
        ::close(sockfd); // 文件描述符(有限)泄漏问题，需要关闭
                        //进程不退出，文件描述符不会自动关闭，一个客户端处理完毕后,应将曾经的文件描述符关闭，否则会导致文件描述符(有限)泄漏，注意文件描述符泄露问题。
    }

                                        //普通类内成员函数这里携带this指针(类内部的成员函数除了static成员方法外，都有this指针)  
    static void* ThreadEntry(void* args)//虽然static成员方法不含this指针可以被pthread_create调用但是不能访问类内部的成员
    {
        pthread_detach(pthread_self());//让线程自己把自己设置为分离,主线程不用管
        ThreadData* data = (ThreadData*)args;
        data->self->HandlerRequest(data->sockfd);
        return nullptr;
        // 默认情况下，线程是 可连接的（Joinable），即主线程（或其他线程）必须调用 pthread_join() 来回收其资源，否则可能导致内存泄漏。
        // 如果线程调用 pthread_detach(pthread_self())，它会主动将自己设置为分离状态，这样退出时系统会自动回收资源，主线程不需要再调用 pthread_join()
    }

    void Start()
    {
        _isrunning = true;
        while (true)
        {
            // TCP不能直接读取数据
            // 1. 先获取新连接
            // 输出型参数client ,用于接受client的网络信息
            struct sockaddr_in client;
            socklen_t client_len = sizeof(client);
            LOG(LogLevel::DEBUG) << "accept ing ...";

            // 真实服务的文件描述符是sockfd ,不是_listensockfd
            // accept获取客户端网络信息, sockfd获取客户端的message信息
            int sockfd = ::accept(_listensockfd, CONV(&client), &client_len);
            if (sockfd < 0)
            {
                LOG(LogLevel::WARNNING) << "accept error: " << strerror(errno);
                continue;
            }

            LOG(LogLevel::INFO) << "accept success, sockfd is : " << sockfd;
            InetAddr ClientAddr(client);
            LOG(LogLevel::INFO) << "Client info" << ClientAddr.Addr();

            // // version-0  只能处理一个客户端的请求
            // HandlerRequest(sockfd);

            // // version-1 :: 多进程处理多个客户端
            // //进程回收的阻塞问题解决方案1:
            // pid_t n =::fork();
            // if(n == 0)//子进程
            // {
            //     ::close(_listensockfd);
            //     if(fork() > 0) exit(0); //子进程退出 ,留下孙子进程
            //      // 孙子进程 -> 孤儿进程 -> 1号进程  解决了父进程要阻塞时等待子进程的僵尸进程问题
            //     HandlerRequest(sockfd); 
            //     exit(0);
            // }

            // ::close(sockfd);
            // //上面子进程创建好孙子进程后 ,会立即退出 ,这里父进程回收子进程不会阻塞
            // int rid =::waitpid(n ,nullptr ,0);//仅仅回收子进程
            // if(rid < 0)
            // {
            //     LOG(LogLevel::WARNNING) << "wait error" ;   
            // }
            // //父进程继续循环处理多个客户端请求


            // //version-2 多线程处理多个客户端请求
            // //一个进程中的所有线程共用同一张文件描述符表，所以不能关闭文件描述符，否则会导致文件描述符(有限)泄漏。 
            // pthread_t tid;
            // ThreadData *data = new ThreadData;//在堆上开辟空间,避免栈上变量的生命周期结束后被释放或者被覆盖
            // data->sockfd = sockfd;
            // data->self = this;  
            // pthread_create(&tid, nullptr, ThreadEntry, data);//sockfd传入问题

            // version-3 线程池版本
            //来了新链接需要构建任务 ,将任务放到线程池中
            task_t f = std::bind(&TcpServer::HandlerRequest,this ,sockfd);//构建任务
            ThreadPool<task_t>::getInstance()->Enqueue(f);

            //ThreadPool<task_t>::getInstance()->Enqueue([this, sockfd]()
            //                                          { this->HandlerRequest(sockfd); });



        }
    }
    ~TcpServer()
    {
    }

private:
    int _listensockfd;
    uint16_t _port;
    bool _isrunning;

    // 处理上层任务的入口
    handler_t _handler;
};

// 下面的版本不能处理多个客户端
//  class TcpServer
//  {
//  public:
//      TcpServer(uint16_t port = gport)
//          : _port(port), _isrunning(false)
//      {
//      }
//      void InitServer()
//      {
//          // 1.创建socket文件
//          _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0); // 没有Int  这里如果定义了一个变量  _sockfd的值就是没有变化的
//          if (_listensockfd < 0)                             // 加 int 会变成局部变量，导致成员变量未被修改。
//          {
//              LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
//              Die(SOCKET_ERR);
//          }
//          LOG(LogLevel::INFO) << "socket success, sockfd is : " << _listensockfd;

//         // 2.1填充网络信息
//         struct sockaddr_in local;
//         memset(&local, 0, sizeof(local)); // 先置零
//         local.sin_family = AF_INET;
//         local.sin_port = htons(_port); // 要被发送给对方的，即要发到网络中！
//         local.sin_addr.s_addr = INADDR_ANY;

//         // 2.2 bind
//         int n = ::bind(_listensockfd, CONV(&local), sizeof(local));
//         if (n < 0)
//         {
//             LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
//             Die(BIND_ERR);
//         }
//         LOG(LogLevel::INFO) << "bind success";

//         // 3. cs,tcp是面向连接的，就要求tcp随时随地等待被连接
//         // tcp 需要将socket设置成为监听状态

//         n = listen(_listensockfd, BACKLOG); // backlog不建议为0 或者太大
//         if (n < 0)
//         {
//             LOG(LogLevel::FATAL) << "listen error";
//             Die(LISTEN_ERR);
//         }
//         LOG(LogLevel::INFO) << "listen success, sockfd is : " << _listensockfd;
//     }
//     void HandlerRequest(int sockfd) //TCP也是全双工的  TCP面向字节流
//     {
//         LOG(LogLevel::INFO)<<"HandlerRequest sockfd is "<<sockfd;
//         char inbuffer[4096];
//         while(true)
//         {
//             ssize_t n =read(sockfd ,inbuffer, sizeof(inbuffer)-1);
//             if(n > 0)
//             {
//                 inbuffer[n]=0;
//                 std::string echo_str ="Server echo#";
//                 echo_str+=inbuffer;
//                 ::write(sockfd ,echo_str.c_str() ,echo_str.size());

//             }
//             else if(n == 0 )
//             {
//                 //read如果返回值为0 ,表示client退出
//                 LOG(LogLevel::INFO)<<"client Quit"<<sockfd;
//                 break;
//             }
//             else
//             {
//                 //read返回值小于0 ,表示读取失败
//                 LOG(LogLevel::WARNNING)<<"read error"<<strerror(errno);
//                 break;
//             }

//         }
//         ::close(sockfd);//文件描述符泄漏问题，需要关闭

//     }
//     void Start()
//     {
//         _isrunning = true;
//         while (true)
//         {
//             // TCP不能直接读取数据
//             // 1. 先获取新连接
//             // 输出型参数client ,用于接受client的网络信息
//             struct sockaddr_in client;
//             socklen_t client_len = sizeof(client);
//             LOG(LogLevel::DEBUG) << "accept ing ...";

//             // 真实服务的文件描述符是sockfd ,不是_listensockfd
//             //accept获取客户端网络信息, sockfd获取客户端的message信息
//             int sockfd = ::accept(_listensockfd, CONV(&client), &client_len);
//             if (sockfd < 0)
//             {
//                 LOG(LogLevel::WARNNING) << "accept error: " << strerror(errno);
//                 continue;
//             }

//             LOG(LogLevel::INFO) << "accept success, sockfd is : " << sockfd;
//             InetAddr ClientAddr(client);
//             LOG(LogLevel::INFO) <<"Client info"<<ClientAddr.Addr();

//             //version-0
//             HandlerRequest(sockfd);
//         }
//     }
//     ~TcpServer()
//     {
//     }

// private:
//     int _listensockfd;
//     uint16_t _port;
//     bool _isrunning;
// };